
// Own header
#include "filecopyoperation.h"

// Qt includes
#include <QDateTime>
#include <QDir>

// Backup2Go includes
#include "trace.h"


/*!
  \class FileCopyOperation
  \brief A thread responsible for copying files.
*/


/*!
  Constructor.
*/
FileCopyOperation::FileCopyOperation(QObject *parent /* = 0 */)
    : QThread(parent),
      m_targetRootPath(QString()),
      m_cancel(false)
{
}


/*!
  Constructor.
*/
FileCopyOperation::FileCopyOperation(QFileInfoList sourceFiles,
                                     QString targetRootPath,
                                     QObject *parent /* = 0 */)
    : QThread(parent),
      m_sourceFiles(sourceFiles),
      m_targetRootPath(targetRootPath),
      m_cancel(false)
{
}


/*!
  Destructor.
*/
FileCopyOperation::~FileCopyOperation()
{
    DEBUG_INFO("Being deleted!");
}


/*!
  Sets \a sourceFiles as the source files to copy.
*/
void FileCopyOperation::setSourceFiles(QFileInfoList sourceFiles)
{

    m_sourceFiles = sourceFiles;
}


/*!
  Sets \a targetRootPath as the root destination where the files will be
  copied to.
*/
void FileCopyOperation::setTargetRootPath(const QString &targetRootPath)
{
    m_targetRootPath = targetRootPath;
}


/*!
  From QThread.
*/
void FileCopyOperation::run()
{
    if (!m_sourceFiles.count() || m_targetRootPath.isEmpty()) {
        DEBUG_INFO("No source files or the target root path missing!");
        return;
    }

    const int count(m_sourceFiles.count());
    QString lastFileCopied = QString();
    QString fileBeingCopied;
    QString temp;
    QString target;
    QFileInfo sourceFileInfo;
    qlonglong totalSizeCopied(0);

    for (int i = 0; (i < count && !m_cancel); ++i) {
        // Extract the source file information.
        fileBeingCopied = m_sourceFiles[i].fileName();
        QFile sourceFile(m_sourceFiles[i].absoluteFilePath());
        sourceFileInfo = QFileInfo(sourceFile);

        if (sourceFileInfo.isFile()) {
            // Signal the status only when copying files.
            emit status(i, totalSizeCopied, lastFileCopied, fileBeingCopied);
        }

        // Get the full path of the source file but if it contains the drive
        // volume, remove the colon.
        temp = m_sourceFiles[i].canonicalFilePath();

        if (temp.contains(':')) {
            temp = '/' + temp.remove(':');
        }

        target = m_targetRootPath + temp;

        // Copy!
        QFile::FileError error = copy(sourceFile, target);

        if (error != QFile::NoError) {
            // Failed to copy the current file!
            DEBUG_INFO("Failed to copy" << fileBeingCopied <<
                       ":" << sourceFile.errorString());

            // Emit the signal containing the error code.
            emit failed(error, fileBeingCopied);

            // Cancel.
            break;
        }

        totalSizeCopied += sourceFileInfo.size();

        if (sourceFileInfo.isFile()) {
            lastFileCopied = fileBeingCopied;
        }
    } // for()

    if (m_cancel) {
        // The operation has been cancelled.
        emit cancelled();
    }

    // Note that the instance will destroy itself!
    deleteLater();
}


/*!
  Copies \a sourceFile to \a target. Returns QFile::NoError if successful,
  QFile::FileError error code otherwise.
*/
QFile::FileError FileCopyOperation::copy(QFile &sourceFile,
                                         const QString &target) const
{
    if (target.isEmpty() || !sourceFile.exists()) {
        // No target specified or the source file does not exist!
        return QFile::FatalError;
    }

    QFileInfo sourceFileInfo(sourceFile);
    bool success(false);

    if (sourceFileInfo.isDir()) {
        // Create the folder.

        if (!QDir(target).exists()) {
            success = QDir().mkpath(target);
        }
        else {
            // Skipping; the folder already exists.
            success = true;
        }
    }
    else {
        // Copy the file.

        // Check if the target file already exists and whether or not it's
        // exactly the same file as the source file.
        QFile targetFile(target);

        if (targetFile.exists()) {
            // A file with the target name already exists.
            if (targetFile.size() == sourceFile.size() &&
                QFileInfo(targetFile).lastModified() ==
                    QFileInfo(sourceFile).lastModified()) {
                // Skipping; the files match.
                success = true;
            }
            else {
                // The files don't match, remove the old file before
                // copying.
                targetFile.remove();
                success = sourceFile.copy(target);
            }
        }
        else {
            success = sourceFile.copy(target);
        }
    }

    if (!success) {
        if (sourceFile.error()) {
            return sourceFile.error();
        }

        return QFile::UnspecifiedError;
    }

    return QFile::NoError;
}


/*!
  Cancels the operation.
*/
void FileCopyOperation::cancel()
{
    DEBUG_POINT;
    m_cancel = true;
}


// End of file.
